#ifndef __M_EXCHANGE_H__
#define __M_EXCHANGE_H__
#include "../mqcommon/helper.hpp"
#include "../mqcommon/log.hpp"
#include "../mqcommon/mq_meg.pb.h"

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <cassert>

namespace pprmq
{
    class Exchange
    {
    public:
        Exchange()
        {
        }
        Exchange(const std::string name, ExchangeType type,const bool durable,const bool auto_delete,
                const google::protobuf::Map<std::string, std::string> args)
            : _name(name), _type(type), _durable(durable), _auto_delete(auto_delete), _args(args)
        {
        }

        // "key=val&key=val"--->存入args中
        void setArgs(const std::string &str_args)
        {
            // 以&为分割符，将分割开的数据存放到result中
            std::vector<std::string> result;
            pprmq::StrHelper::split(str_args, "&", result);
            for (auto &str : result)
            {
                size_t pos = str.find("=");
                std::string key = str.substr(0, pos);
                std::string value = str.substr(pos + 1);
                _args[key] = value;
            }
        }

        // 从args中拿出数据，转化为字符串
        std::string getArgs()
        {
            std::string result;
            for (auto &[key, val] : _args)
            {
                result += key + "=" + val + "&";
            }
            return result;
        }

    public:
        using ptr = std::shared_ptr<Exchange>;              // 智能指针管理
        std::string _name;                                  // 交换机名称（唯一标识）
        ExchangeType _type;                                 // 交换机类型（如direct、topic、fanout等）
        bool _durable;                                      // 持久化标志（true：服务重启后不丢失；false：仅存于内存）
        bool _auto_delete;                                  // 自动删除标志（当最后一个绑定的队列被删除时，自动删除交换机）
        google::protobuf::Map<std::string, std::string> _args; // 附加参数（键值对，如路由规则参数）
    };

    using ExchangeMap = std::unordered_map<std::string, Exchange::ptr>;
    // 保证数据持久化传输---数据存储在sqlite数据库中
    class ExchangeMapper
    {
    public:
        ExchangeMapper(const std::string &dbfile) : _sql_helper(dbfile)
        {
            // 获取文件父目录
            std::string path = pprmq::FileHelper::parentDirectory(dbfile);
            // 创建文件
            pprmq::FileHelper::createDirectory(path); // 确保目录存在
            // 打开数据库
            assert(_sql_helper.open());
            // 创建交换机表
            createTable();
        }

        void createTable()
        {
#define CREATE_TABLE "create table if not exists exchange_table(\
            name varchar(32) primary key,\
            type int,\
            durable int,\
            auto_delete int,\
            args varchar(128));"
            bool ret = _sql_helper.exec(CREATE_TABLE, nullptr, nullptr);
            if (!ret)
            {
                DLOG("创建交换机数据库表失败");
                abort(); // 直接异常退出程序
            }
        }
        void removeTable()
        {
#define DROP_TABLE "drop table if exists exchange_table;"
            bool ret = _sql_helper.exec(DROP_TABLE, nullptr, nullptr);
            if (!ret)
            {
                DLOG("删除交换机数据库表失败");
                abort(); // 直接异常退出程序
            }
        }
        bool insert(Exchange::ptr &exp)
        {
            std::stringstream ss;
            ss << "insert into exchange_table values(";
            ss << "'" << exp->_name << "',";
            ss << exp->_type << ",";
            ss << exp->_durable << ",";
            ss << exp->_auto_delete << ",";
            ss << "'" << exp->getArgs() << "');";
            return _sql_helper.exec(ss.str(), nullptr, nullptr);
        }
        void remove(const std::string &name)
        {
            std::stringstream ss;
            ss << "delete from exchange_table where name=";
            ss << "'" << name << "'";
            _sql_helper.exec(ss.str(), nullptr, nullptr);
        }

        // 从数据库恢复所有交换机数据到内存（服务启动时调用）
        ExchangeMap recovery()
        {
            ExchangeMap result;
            std::string sql = "select name, type, durable, auto_delete, args from exchange_table;";
            _sql_helper.exec(sql, SelectCallback, &result);
            return result;
        }

    private:
        static int SelectCallback(void *args, int col, char **row, char **fields)
        {
            ExchangeMap *result = (ExchangeMap *)args;
            auto exp = std::make_shared<Exchange>();
            exp->_name = row[0];
            exp->_type = (pprmq::ExchangeType)std::stoi(row[1]);
            exp->_durable = (bool)std::stoi(row[2]);
            exp->_auto_delete = (bool)std::stoi(row[3]);
            if (row[4])
                exp->setArgs(row[4]);
            result->insert(std::make_pair(exp->_name, exp));
            return 0;
        }

    private:
        Sqlitehelper _sql_helper;
    };

    class ExchangeManager
    {
    public:
        using ptr = std::shared_ptr<ExchangeManager>;
        ExchangeManager(const std::string &dbfile) : _mapper(dbfile)
        {
            _exchanges = _mapper.recovery();
        }
        // 声明交换机
        bool declareExchange(const std::string &name,
                             ExchangeType type,
                             bool durable, bool auto_delete,
                             const google::protobuf::Map<std::string, std::string> &args)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 判断交换机是否存在
            auto it = _exchanges.find(name);
            if (it != _exchanges.end())
            {
                // 交换机已存在，找到就不需要创建，直接返回
                return true;
            }
            // 1. 创建交换机智能指针对象
            auto exp = std::make_shared<Exchange>(name, type, durable, auto_delete, args);
            // 2. 若需持久化，先存入数据库（失败则返回false）
            if (durable)
            {
                bool ret = _mapper.insert(exp);
                if (!ret)
                    return false;
            }
            // 3. 存入内存哈希表
            _exchanges.insert(std::make_pair(name, exp));
            return true;
        }

        // 删除交换机
        void deleteExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it == _exchanges.end())
            {
                // 交换机不存在，不需要删除，直接返回
                return;
            }
            // 如果有数据持久化，就需要将数据库中的数据清理
            if (it->second->_durable == true)
                _mapper.remove(name);
            _exchanges.erase(name);
        }
        // 获取指定交换机对象
        Exchange::ptr selectExchange(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it != _exchanges.end())
            {
                // 找到了
                return it->second;
            }
            return Exchange::ptr();
        }
        // 返回内存中交换机的总数（用于监控或统计）
        size_t size()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _exchanges.size();
        }
        // 判断交换机是否存在
        bool exists(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _exchanges.find(name);
            if (it != _exchanges.end())
            {
                return true;
            }
            return false;
        }
        // 清理所有交换机数据
        void clear()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _exchanges.clear();
        }

    private:
        std::mutex _mutex;      // 加锁保护，线程安全
        ExchangeMapper _mapper; // 持久化管理器，与数据库交互的桥梁
        ExchangeMap _exchanges; // 内存交换机存储（哈希表，key=交换机名称，value=智能指针）
    };
}
#endif